package com.baijiaoxi.common.model.request;

import com.baijiaoxi.common.model.UUID;
import com.baijiaoxi.common.model.headerfiller.FillByHeaders;
import com.baijiaoxi.common.utils.jdk.Strings;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Data
public class RequestInfo implements Serializable {
    protected String requestId;//请求id
    protected String title;//
    protected String uri;//请求地址或mq的topic
    protected String method;//请求方式
    protected String ip;//ip地址
    protected Object requestBody;//请求参数
    protected Object[] args;//请求参数
    protected Map<String, String> headers = new HashMap<>();//请求头
    protected Map<String, String> querymap = new HashMap<>();//url参数
    protected Long startTime;//请求开始时间
    protected Long endTime;//请求结束时间
    protected Long costTime;//请求耗时
    protected Long userId;//发起请求的用户id
    protected String userIdStr;//发起请求的用户id
    protected Long weappId;//多租户，租户id
    protected Map<String, Object> extra;//额外信息
    protected String sign;
    protected String responseMsg;
    protected int responseStatus;
    protected int responseErrCode;
    protected String responseResult;
    protected Boolean approved;
    @JsonIgnore
    protected FillByHeaders fillByHeaders;
    protected Long accountId;
    protected Long productId;
    protected WXMsg wxMsg;


    @JsonIgnore
    public Date getStartTimeAsDate() {
        if (this.startTime == null)
            return null;
        return new Date(this.startTime);
    }

    @JsonIgnore
    public <T> T getExtraData(String key) {
        return extra == null ? null :
                extra.get(key) == null ? null :
                        (T) extra.get(key);
    }

    public RequestInfo addExtraData(String key, Object val) {
        if (extra == null)
            extra = new HashMap<>();
        extra.put(key, val);
        return this;
    }

    public RequestInfo() {
        this.requestId = UUID.uuid();
    }

    public RequestInfo(String requestId) {
        this.requestId = requestId;
    }

    public RequestInfo(HttpServletRequest request) {
        String requestId = UUID.uuid();
        init(request, requestId);
    }

    public RequestInfo(HttpServletRequest request, String requestId) {
        init(request, requestId);
    }

    protected void init(HttpServletRequest request, String requestId) {
        this.requestId = requestId;
        if (request != null) {
            this.startTime = System.currentTimeMillis();
            this.method = request.getMethod();
            this.uri = request.getRequestURI().replace("//", "/");

            String queryString = request.getQueryString();
            if (!Strings.isNullOrEmpty(queryString)) {
                this.querymap = new HashMap<>();
                String[] pairs = queryString.split("&");
                for (String pair : pairs) {
                    int idx = pair.indexOf("=");
                    String key = URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8);
                    String value = URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8);
                    this.querymap.put(key, value);
                }
            }
            Map<String, String[]> paramsMap = request.getParameterMap();
            if (paramsMap != null && !paramsMap.isEmpty()) {
                this.uri += "?";
                this.uri += String.join("&",
                        paramsMap.keySet().stream().map(key -> {
                                    String[] vals = paramsMap.get(key);
                                    return String.join("&", Arrays.stream(vals).map(val -> String.format("%s=%s", key, val)).collect(Collectors.toList()));
                                })
                                .collect(Collectors.toList()));
            }
            Enumeration<String> headerNames = request.getHeaderNames();

            while (headerNames.hasMoreElements()) {// 判断是否还有下一个元素
                String nextElement = headerNames.nextElement();// 获取headerNames集合中的请求头
                this.headers.put(nextElement, URLDecoder.decode(request.getHeader(nextElement), StandardCharsets.UTF_8));
            }
            this.ip = getRemoteAddr(request);
            initField();
        }
    }

    protected void initField() {
        this.productId = getHeaderValueToLong("productid");
        if (this.productId.equals(0L)) {
            this.productId = getHeaderValueToLong("productId");
        }
        this.accountId = getHeaderValueToLong("accountid");
        if (this.accountId.equals(0L)) {
            this.accountId = getHeaderValueToLong("accountId");
        }
        this.weappId = getHeaderValueToLong("weappid");
        if (this.weappId.equals(0L)) {
            this.weappId = getHeaderValueToLong("weappId");
        }
        this.userId = getHeaderValueToLong("userid");
        if (this.userId.equals(0L)) {
            this.userId = getHeaderValueToLong("userId");
        }
        this.userIdStr = getHeaderValue("userid");
        if (Strings.isNullOrEmpty(this.userIdStr)) {
            this.userIdStr = getHeaderValue("userId");
        }
        this.sign = this.headers.get("sign");
    }

    protected static final String[] ADDR_HEADER = {"X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP",
            "X-Real-IP"};
    protected static final String NUKNOWN = "unknown";

    public static String getRemoteAddr(HttpServletRequest request) {
        String addr = null;
        for (String header : ADDR_HEADER) {
            if (Strings.isNullOrEmpty(addr) || NUKNOWN.equalsIgnoreCase(addr)) {
                addr = request.getHeader(header);
            } else {
                break;
            }
        }
        if (Strings.isNullOrEmpty(addr) || NUKNOWN.equalsIgnoreCase(addr)) {
            addr = request.getRemoteAddr();
        } else {
            // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按','分割
            if (addr != null) {
                int i = addr.indexOf(",");
                if (i > 0) {
                    addr = addr.substring(0, i);
                }
            }
        }
        return addr;
    }

    public String getQueryParam(String key) {
        if (this.querymap == null)
            return null;
        return this.querymap.get(key);
    }

    public Long getHeaderValueToLong(String code) {
        return getLongValueHeader(this.headers, code);
    }

    public String getHeaderValue(String code) {
        return getHeaderValue(this.headers, code);
    }


    public Integer getHeaderValueToInteger(String code) {
        return getHeaderValueToInteger(this.headers, code);
    }

    public static String getHeaderValue(Map<String, String> headers, String code) {
        String value = headers.get(code);
        return value == null ? "" : value;
    }

    public static Long getLongValueHeader(Map<String, String> headers, String code) {
        String str = headers.get(code);

        Long value;
        try {
            value = Long.valueOf(str);
        } catch (Exception var5) {
            log.error(code + ">>>" + str);
            value = 0L;
        }

        return value;
    }

    public static Integer getHeaderValueToInteger(Map<String, String> headers, String code) {
        Integer value;
        String str = headers.get(code);
        try {
            value = Integer.valueOf(str);
        } catch (Exception e) {
            //   log.error(code + ">>>" + str);
            value = 0;
        }
        return value;
    }
}
